#ifndef AFCORE_DATABASE_DATABASE_DATABASE_PREPAREDSTATEMENT_
#define AFCORE_DATABASE_DATABASE_DATABASE_PREPAREDSTATEMENT_

#include <vector>
#include <future>

#include "define.h"
#include "database_sql_op.h"
#include "nocopyable.h"

namespace afcore {

/// @brief  数据库
namespace database {

/// @brief  缓冲区数据联合体
/// @note   (upper-level bind -> queue -> lower-level bind)
union UPreparedStatementDataUnion {
  bool boolean;
  uint8_t ui8;
  int8_t i8;
  uint16_t ui16;
  int16_t i16;
  uint32_t ui32;
  int32_t i32;
  uint64_t ui64;
  int64_t i64;
  float f;
  double d;
};

/// @brief  准备状态值类型
/// @note   区分 UPreparedStatementDataUnion类型
enum EPreparedStatementValueType {
  kPreparedStatementValueType_Bool,
  kPreparedStatementValueType_Ui8,
  kPreparedStatementValueType_Ui16,
  kPreparedStatementValueType_Ui32,
  kPreparedStatementValueType_Ui64,
  kPreparedStatementValueType_I8,
  kPreparedStatementValueType_I16,
  kPreparedStatementValueType_I32,
  kPreparedStatementValueType_I64,
  kPreparedStatementValueType_Float,
  kPreparedStatementValueType_Double,
  kPreparedStatementValueType_String,
  kPreparedStatementValueType_Binary,
  kPreparedStatementValueType_Null,
};

/// @brief  准备状态数据
struct SPreparedStatementData {
  UPreparedStatementDataUnion data;   ///< 数据
  EPreparedStatementValueType type;   ///< 类型
  std::vector<uint8_t> binary;        ///< 二进制数据
};

class CPreparedStatementMysql;

/// @brief  预处理状态基类
/// @note   上层类 Upper-level
class AFCORE_DATABASE_API CPreparedStatementBase
  : public CNocopyable {
  friend class CPreparedStatementTask;
  friend class CPreparedStatementMysql;
  friend class CMysqlConnection;
public:
  explicit CPreparedStatementBase(uint32_t index, uint8_t capacity);
  virtual ~CPreparedStatementBase();

  void SetNull(const uint8_t index);
  void SetBool(const uint8_t index, const bool value);
  void SetUInt8(const uint8_t index, const uint8_t value);
  void SetUInt16(const uint8_t index, const uint16_t value);
  void SetUInt32(const uint8_t index, const uint32_t value);
  void SetUInt64(const uint8_t index, const uint64_t value);
  void SetInt8(const uint8_t index, const int8_t value);
  void SetInt16(const uint8_t index, const int16_t value);
  void SetInt32(const uint8_t index, const int32_t value);
  void SetInt64(const uint8_t index, const int64_t value);
  void SetFloat(const uint8_t index, const float value);
  void SetDouble(const uint8_t index, const double value);
  void SetString(const uint8_t index, const std::string& value);
  void SetBinary(const uint8_t index, const std::vector<uint8_t>& value);

  uint32_t GetIndex() const { return index_; }

protected:
  void BindParameters(CPreparedStatementMysql* stmt);
protected:
  CPreparedStatementMysql* stmt_ {nullptr};              ///< mysql预处理信息
  uint32_t index_ {0};                                  ///< 索引
  std::vector<SPreparedStatementData> statement_data_;  ///< 缓冲区数据 并未绑定到mysql
};

template<typename T>
class CPreparedStatement
  : public CPreparedStatementBase {
public:
  explicit CPreparedStatement(uint32_t index, uint8_t capacity)
    : CPreparedStatementBase(index, capacity) {
  }
};

/// @brief  准备状态任务
/// @note   底层类 可排队 Lower-level
class AFCORE_DATABASE_API CPreparedStatementTask
  : public CSqlOperation {
public:
  CPreparedStatementTask(CPreparedStatementBase* stmt, bool async = false);
  ~CPreparedStatementTask();

  bool Execute() override;
  RPreparedQueryResultFutrue GetFuture() { return result_->get_future(); }
private:
  CPreparedStatementBase* stmt_ {nullptr};
  bool has_result_ {false};
  RPreparedQueryResultPromise* result_ {nullptr};
};

} // !namespace database

} // !namespace afcore

#endif //! AFCORE_DATABASE_DATABASE_DATABASE_PREPAREDSTATEMENT_